package com.dkm.dkmproject.action;

import cn.minsin.wechat.wechatpay.core.util.Sha1Util;
import com.alibaba.fastjson.JSONObject;
import com.dkm.dkmproject.domain.OrderTb;
import com.dkm.dkmproject.service.IOrderTbService;
import com.dkm.dkmproject.utils.WechatGongutils.*;
import com.dkm.dkmproject.utils.Wechatutils.*;
import org.omg.CORBA.portable.ResponseHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;

import java.text.DecimalFormat;
import java.util.*;

/**
 * @PROJECT_NAME: dkmproject
 * @DESCRIPTION:
 * @USER: 周佳佳
 * @DATE: 2020/6/3 19:06
 */
@Controller
@RequestMapping("/paycontroller")
public class PlayController {
    Logger logger= (Logger) LoggerFactory.getLogger(PlayController.class);
    @Autowired
    IOrderTbService orderTbService;
    /**
     * h5 支付 返回一个微信支付链接
     * 返回的链接要拼接 具体前端怎么拼看这个文章https://www.cnblogs.com/dragondean/p/10220804.html
     * @param request
     * @param totalAmount
     * @return
     */
    @ResponseBody
    @CrossOrigin
    @RequestMapping("/pay")
    public String weixinPayWap(HttpServletRequest request, @RequestParam(value = "totalAmount", required = false) BigDecimal totalAmount) {
        String APPID = "wxd10f20b209978883";
        String MERID = "1595596021";
        String SIGNKEY = "JBqeTQCigJJSl3BtPUbdSl0prStjM54Q";
        String spbill_create_ip = IpUtils.getIpAddr(request);// 本机的ip地址

        System.out.println("spbill_create_ip="+spbill_create_ip);
        //String spbill_create_ip = "";//测试地址，也就是本地真是ip，用于本地测试用
        String scene_info = "{\"h5_info\": {\"type\":\"Wap\",\"wap_url\": \"http://www.mhdwx.com/paycontroller/pay/\t\",\"wap_name\": \"信息认证\"}}";//我这里是网页入口，app入口参考文档的安卓和ios写法
        String tradeType = "MWEB";//H5支付标记
        String MD5 = "JSAPI";//虽然官方文档不是必须参数，但是不送有时候会验签失败
        JSONObject result = new JSONObject();

        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        //金额转化为分为单位 微信支付以分为单位
        String finalmoney =""+((totalAmount.multiply(new BigDecimal("100")).setScale(0, BigDecimal.ROUND_HALF_UP).intValue()));// 支付金额，单位：分，这边需要转成字符串类型，否则后面的签名会失败
        int randomNum  = (int) (Math.random() * 1999+5000);
        String out_trade_no = TimeUtils.getSysTime("yyyyMMddHHmmss") + randomNum;
        //随机数
        String nonce_str= MD5Utils.getMessageDigest(String.valueOf(new Random().nextInt(10000)).getBytes());
        //签名数据
        Map<String, String> packageParams = new HashMap<String, String>();
        packageParams.put("appid",APPID);
        packageParams.put("mch_id",MERID);
        packageParams.put("nonce_str",nonce_str);
        packageParams.put("out_trade_no",out_trade_no);
        packageParams.put("total_fee",finalmoney);
        packageParams.put("spbill_create_ip",spbill_create_ip);
        packageParams.put("notify_url","https://www.mhdwx.com/paycontroller/notify");
        packageParams.put("trade_type",tradeType);
        packageParams.put("body","测试");
        packageParams.put("scene_info",scene_info);
        // 除去数组中的空值和签名参数
        packageParams = PayUtil.paraFilter(packageParams);
        String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串

        // MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
        String mysign = PayUtil.sign(prestr, WxPayConfig.key, "utf-8").toUpperCase();
        System.out.println("=======================第一次签名：" + mysign + "=====================");
      /*  packageParams.put("sign_type","MD5");
        packageParams.put("key",SIGNKEY);*/
        packageParams.put("sign", mysign);

        String requestXML = PayCommonUtil.getRequestXml(packageParams);
        System.out.println(requestXML);
       /* //签名MD5加密

        //封装xml报文
        String xml="<xml>"+
                "<appid>"+ APPID+"</appid>"+
                "<mch_id>"+ MERID+"</mch_id>"+
                "<nonce_str>"+nonce_str+"</nonce_str>"+
                "<sign>"+mysign+"</sign>"+
                "<body>"+"测试"+"</body>"+
                "<out_trade_no>"+out_trade_no+"</out_trade_no>"+
                "<total_fee>"+finalmoney+"</total_fee>"+
                "<trade_type>"+tradeType+"</trade_type>"+
                "<notify_url>"+"https://www.mhdwx.com/paycontroller/notify"+"</notify_url>"+
                "<sign_type>MD5</sign_type>"+
                "<scene_info>"+scene_info+"</scene_info>"+
                "<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"+
                "</xml>";
        System.out.println(xml);*/
        String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信统一下单接口
        String mweb_url = "";
        Map map = new HashMap();
        try {
            //预下单 获取接口地址
            map = WebUtilsone.getMwebUrl(createOrderURL, requestXML);
            String return_code  = (String) map.get("return_code");
            String return_msg = (String) map.get("return_msg");
            if("SUCCESS".equals(return_code) && "OK".equals(return_msg)){
                mweb_url = (String) map.get("mweb_url");//调微信支付接口地址
                System.out.println("mweb_url="+mweb_url);
            }else{
                System.out.println("统一支付接口获取预支付订单出错");
                result.put("msg", "支付错误");
                return result.toString();
            }
        } catch (Exception e) {
            System.out.println("统一支付接口获取预支付订单出错");
            result.put("msg", "支付错误");
            return result.toString();
        }
        result.put("mwebUrl",mweb_url);

        //添加微信支付记录日志等操作


        result.put("msg", "success");
        return result.toString();
    }


    @ResponseBody
    @RequestMapping("notify")
    @CrossOrigin
    public void weixinPayNotify(HttpServletRequest request, HttpServletResponse response){
        BufferedReader reader = null;
        try {
            reader = request.getReader();
        } catch (IOException e) {
            e.printStackTrace();
        }
        String line = "";
        Map map = new HashMap();
        String xml = "<xml><return_code><![CDATA[FAIL]]></xml>";;
        JSONObject dataInfo = new JSONObject();
        StringBuffer inputString = new StringBuffer();
        while (true) {
            try {
                if (!((line = reader.readLine()) != null)) break;
            } catch (IOException e) {
                e.printStackTrace();
            }
            inputString.append(line);
        }
        try {
            request.getReader().close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("----接收到的报文---"+inputString.toString());
        if(inputString.toString().length()>0){
            map = XMLUtils.parseXmlToList(inputString.toString());
        }else{
            System.out.println("接受微信报文为空");
        }
        System.out.println("map="+map);
        if(map!=null && "SUCCESS".equals(map.get("result_code"))){
            //成功的业务。。。
            xml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
        }else{
            //失败的业务。。。
        }
        //告诉微信端已经确认支付成功
        try {
            response.getWriter().write(xml);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 元转分
     * @param price
     * @return
     */
    public static Integer changeY2F(double price) {
        DecimalFormat df = new DecimalFormat("#.00");
        price = Double.parseDouble(df.format(price));
        Integer money = (int) (price * 100);
        return money;
    }

 /*   *//**
     * @Description: 发起微信支付
     * @param openid
     * @param request
     *//*
    @RequestMapping("/WeChatPay")
    @ResponseBody
    public Json wxPay(@RequestParam(value = "openid", required = false) String openid,
            @RequestParam(value = "price", required = false) BigDecimal price ,HttpServletRequest request) {
        // Map<String, Object> orderInfoByOrderId = shoppingService.getOrderInfoByOrderId(orderId);
        // JSONObject jsonObject = new JSONObject(orderInfoByOrderId);
        // 先根据orderId查询出订单信息
        String payment =""+((price.multiply(new BigDecimal("100")).setScale(0, BigDecimal.ROUND_HALF_UP).intValue()));// 支付金额，单位：分，这边需要转成字符串类型，否则后面的签名会失败
        int randomNum  = (int) (Math.random() * 1999+5000);

        String orderId = TimeUtils.getSysTime("yyyyMMddHHmmss") + randomNum;
        Json json = new Json();
        String SIGNKEY = "JBqeTQCigJJSl3BtPUbdSl0prStjM54Q";
        try {
            String body="测试";
            String nonce_str = StringUtils.getRandomStringByLength(32);// 32位随机字符串
            String spbill_create_ip = IpUtils.getIpAddr(request);// 本机的ip地址
            Map<String, String> packageParams = new HashMap<String, String>();
            packageParams.put("appid", WxPayConfig.appid); // 公众号appid
            packageParams.put("body", body); // 订单名称
            packageParams.put("mch_id", WxPayConfig.mch_id); // 微信支付的商户id
            packageParams.put("nonce_str", nonce_str);// 32位随机字符串
            packageParams.put("openid", openid);
            packageParams.put("out_trade_no", orderId);// 商户订单号
            packageParams.put("spbill_create_ip", spbill_create_ip); // 本机的ip地址
            packageParams.put("total_fee", payment); // 支付金额，这边需要转成字符串类型，否则后面的签名会失败
            packageParams.put("notify_url", WxPayConfig.notify_url); // 支付成功后的服务器回调url
            packageParams.put("trade_type", WxPayConfig.TRADETYPE); // 交易类型

            // 除去数组中的空值和签名参数
            packageParams = PayUtil.paraFilter(packageParams);
            String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串

            // MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
            String mysign = PayUtil.sign(prestr, WxPayConfig.key, "utf-8").toUpperCase();
            logger.info("=======================第一次签名：" + mysign + "=====================");

            // 拼接统一下单接口使用的xml数据，要将上一步生成的签名一起拼接进去
            String xml = "<xml>" + "<appid>" + WxPayConfig.appid + "</appid>" + "<body><![CDATA[" + body + "]]></body>"
                    + "<mch_id>" + WxPayConfig.mch_id + "</mch_id>" + "<nonce_str>" + nonce_str + "</nonce_str>"
                    + "<notify_url>" + WxPayConfig.notify_url + "</notify_url>" + "<openid>" + openid + "</openid>"
                    + "<out_trade_no>" + orderId + "</out_trade_no>" + "<spbill_create_ip>" + spbill_create_ip
                    + "</spbill_create_ip>" + "<total_fee>" + payment + "</total_fee>" + "<trade_type>"
                    + WxPayConfig.TRADETYPE + "</trade_type>" + "<sign>" + mysign + "</sign>" + "</xml>";


            // 调用统一下单接口，并接受返回的结果
            String result = PayUtil.httpRequest(WxPayConfig.pay_url, "POST", xml);


            // 将解析结果存储在HashMap中
            Map map = PayUtil.doXMLParse(result);

            String return_code = (String) map.get("return_code");// 返回状态码

            // 返回给移动端需要的参数
            Map<String, Object> response = new HashMap<String, Object>();
            if (return_code == "SUCCESS" || return_code.equals(return_code)) {
                // 业务结果
                String prepay_id = (String) map.get("prepay_id");// 返回的预付单信息
                response.put("nonceStr", nonce_str);
                response.put("package", "prepay_id=" + prepay_id);
                // response.put("package", prepay_id);
                Long timeStamp = System.currentTimeMillis() / 1000;
                response.put("timeStamp", timeStamp + "");// 这边要将返回的时间戳转化成字符串，不然小程序端调用wx.requestPayment方法会报签名错误

                String stringSignTemp = "appId=" + WxPayConfig.appid + "&nonceStr=" + nonce_str + "&package=prepay_id="
                        + prepay_id + "&signType=" + WxPayConfig.SIGNTYPE + "&timeStamp=" + timeStamp;
                // 再次签名，这个签名用于小程序端调用wx.requesetPayment方法
                String paySign = PayUtil.sign(stringSignTemp, WxPayConfig.key, "utf-8").toUpperCase();
                logger.info("=======================第二次签名：" + paySign + "=====================");

                response.put("paySign", paySign);
                // 更新订单信息
                // 业务逻辑代码
            }
            response.put("appid", WxPayConfig.appid);

            json.setSuccess(true);
            json.setData(response);
        } catch (Exception e) {
            e.printStackTrace();
            json.setSuccess(false);
            json.setMsg("发起失败");
        }
        return json;
    }

    *//**
     * @Description:微信支付回调
     * @return
     * @throws Exception
     * @throws Exception
     *//*
    @RequestMapping(value = "/WeChatNotify")
    @ResponseBody
    public void wxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()));
        String line = null;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();
        // sb为微信返回的xml
        String notityXml = sb.toString();

        Map map = PayUtil.doXMLParse(notityXml);

        String returnCode = (String) map.get("return_code");
        if ("SUCCESS".equals(returnCode)) {
            //验证签名是否正确
            Map<String, String> validParams = PayUtil.paraFilter(map);  //回调验签时需要去除sign和空值参数
            String validStr = PayUtil.createLinkString(validParams);//把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
            String sign = PayUtil.sign(validStr, WxPayConfig.key, "utf-8").toUpperCase();//拼装生成服务器端验证的签名

            // 验证签名是否正确
            if (sign.equals(map.get("sign"))) {
                *//** 此处添加自己的业务逻辑代码start **//*

                //String transaction_id = map.get("transaction_id").toString(); //微信支付交易号
                //String out_trade_no = map.get("out_trade_no").toString(); //商户订单号
                // shoppingService.updateOrderStateByOrderId(map.get("out_trade_no").toString(), 12, map.get("transaction_id").toString());
                *//** 此处添加自己的业务逻辑代码end **//*

                // 通知微信服务器已经支付成功
                response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");
                response.getWriter().flush();
                response.getWriter().close();
            }else{
                response.getWriter().write("<xml><return_code><![CDATA[FAIL]]></return_code></xml>");
                response.getWriter().flush();
                response.getWriter().close();
            }
        } else {
            response.getWriter().write("<xml><return_code><![CDATA[FAIL]]></return_code></xml>");
            response.getWriter().flush();
            response.getWriter().close();
        }
    }
*/
    @RequestMapping("/wxPay")
    public void wxPay(HttpServletRequest request,HttpServletResponse response,
                      @RequestParam(value = "token", required = false)   String token
          /*  , @RequestParam(value = "totalAmount", required = false) BigDecimal totalAmount*/
    , @RequestParam(value = "orId", required = false) String orId) throws Exception{
        //先根据订单id查询总金额
        OrderTb orderTb=orderTbService.selectByPrimaryKey(orId);
       /* int randomNum  = (int) (Math.random() * 1999+5000);
        String orderNo = TimeUtils.getSysTime("yyyyMMddHHmmss") + randomNum;*/
        System.out.println("开始支付");
        System.out.println("请求参数orderNo："+orId+"token："+token);
        String spbill_create_ip = IpUtils.getIpAddr(request);// 本机的ip地址

        String appid = "wxd10f20b209978883";
        String mch_id = "1595596021";
        String mch_key ="JBqeTQCigJJSl3BtPUbdSl0prStjM54Q";
        //jsapi接口初始化
        RequestHandler requestHandler=new RequestHandler(request, response);
        XMLHelper xh;
        requestHandler.init();
        requestHandler.init(appid, mch_key);

            String totalFee= orderTb.getOrMoney().multiply(new BigDecimal(100)).setScale(0,BigDecimal.ROUND_HALF_UP) + "";
            //随机字符串
            String noncestr = Sha1Util.getNonceStr();
            //时间串
            String timestamp = Sha1Util.getTimeStamp();
            //回调地址，需要改成自己的
            String notify= "https://mhdwx.com/paycontroller/notify.ohtml";
            System.out.println("回调地址："+notify);
            //===============
            //已支付接口参数
            //===============
            requestHandler.setParameter("appid", appid);  //公众号	必填
            requestHandler.setParameter("mch_id", mch_id);  //商户号	必填
            requestHandler.setParameter("nonce_str", noncestr);  //随机字符串	必填
            requestHandler.setParameter("body", "商品订单");  //商品描述	必填
            requestHandler.setParameter("out_trade_no", orId);  //商户系统内部的订单号 必填
            requestHandler.setParameter("total_fee", totalFee);  //订单总金额，单位为分不能带小数点	必填
            requestHandler.setParameter("spbill_create_ip", spbill_create_ip);  //订单生成的机器IP	必填
            requestHandler.setParameter("notify_url", notify);  //接收支付成功通必填
            requestHandler.setParameter("trade_type", "JSAPI");  //支付类型	必填
            requestHandler.setParameter("openid", token);  //用户唯一标识（trade_type为JSAPI时必填）
            //参数转换为xml格式
            String xmlParams=requestHandler.getRequestURL();
            //预支付提交地址
            String url="https://api.mch.weixin.qq.com/pay/unifiedorder";
            //预支付请求
             String  json = WebUtilsone.getHttpData(url, xmlParams);
          //  String json=HttpRequestHelper.postData(url, xmlParams, "utf-8");
            System.out.println("参数信息"+json);
            //转换为xml
            xh=new XMLHelper(json,"UTF-8");

            // 将解析结果存储在HashMap中
            Map map = PayUtil.doXMLParse(json);
            String return_code = (String) map.get("return_code");//返回状态码
            System.out.println("return_code的值是"+return_code);

            //预支付id
            String prepay_id = xh.readByName("prepay_id");
            //获取package包
            String packageValue = "prepay_id="+prepay_id;
            //微信支付参数
            SortedMap<String, String> signParams = new TreeMap<String, String>();
            signParams.put("appId", appid);
            signParams.put("nonceStr", noncestr);
            signParams.put("package", packageValue);
            signParams.put("timeStamp", timestamp);
            signParams.put("signType", "MD5");
            //生成支付签名
            String sign = requestHandler.createSign(signParams);
            //增加非参与签名的额外参数
            signParams.put("paySign", sign);
            StringBuffer sb = new StringBuffer();
            sb.append("{");
            sb.append("\"appId\":\"");sb.append(appid);sb.append("\",");
            sb.append("\"timeStamp\":\"");sb.append(timestamp);sb.append("\",");
            sb.append("\"nonceStr\":\"");sb.append(noncestr);sb.append("\",");
            sb.append("\"package\":\"");sb.append(packageValue);sb.append("\",");
            sb.append("\"signType\":\"");sb.append("MD5");sb.append("\",");
            sb.append("\"paySign\":\"");sb.append(sign);sb.append("\"");
            sb.append("}");
            System.out.println("前台输出"+sb.toString());
            WebUtils.toPageJson(response, sb.toString());
    }
    @SuppressWarnings({ "static-access", "unused" })
    @RequestMapping(value="/notify.ohtml",method = RequestMethod.POST)
    public void notify(HttpServletRequest request,HttpServletResponse response ) throws Exception
    {
        System.out.println("支付回调");

        //解析xml
        InputStream a=request.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(a,"UTF-8"));
        StringBuilder sb = new StringBuilder();
        String line = null;
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
        //xml帮助类
        XMLHelper xh=new XMLHelper(sb.toString(),"UTF-8");
        System.out.println("返回的参数："+sb.toString());
        //订单号
        String orderNo = xh.readByName("out_trade_no");
        String tradeNo = xh.readByName("transaction_id");
        String totalFee = xh.readByName("total_fee");
        //状态码
        String resultCode = xh.readByName("result_code");
        String sign = xh.readByName("sign");
      /*  ResponseHandler rsh=new ResponseHandler();
        String mySign=rsh.createSign(rsh.parseXml(sb.toString()));*/
        //+mySign
        System.out.println("订单号："+orderNo+"，状态码："+resultCode+"，sign签名："+sign+"，mySign签名");
        if(resultCode.equals("SUCCESS")&&!sign.equals("")){
            System.out.println("进成功判断了");
            BigDecimal amount=(new BigDecimal(totalFee)).divide(new BigDecimal("100")).setScale(2,BigDecimal.ROUND_HALF_UP);//微信支付的单位是分 转化为元 保留两位小数
            WebUtils.toPageText(response, "success");
            OrderTb orderTb=new OrderTb();
            orderTb.setOrState(1);
            orderTb.setOrId(tradeNo);
            int rows=orderTbService.updateByPrimaryKeySelective(orderTb);
            if(rows>0){
                WebUtils.toPageText(response, "支付成功!");
            }else{
                WebUtils.toPageText(response, "fail");
            }

        }else{
            System.out.println("进失败判断了");
            WebUtils.toPageText(response, "fail");
        }
    }
}
